﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using MotionCS.Helper;
using MotionCS.Enumerate;
using MvCamCtrl.NET;
using MvCamCtrl.NET.CameraParams;

namespace MotionCS.CameraVision
{
    public class HikvisionData : IFrameData
    {
        /// <summary>
        /// 相机序列号
        /// </summary>
        private string serialNo;
        public string SerialNo
        {
            get => serialNo;
            set
            {
                if (value != serialNo)
                {
                    serialNo = value;
                }
            }
        }
        /// <summary>
        /// 相机序列号
        /// </summary>
        private string deviceIp;
        public string DeviceIp
        {
            get => deviceIp;
            set
            {
                if (value != deviceIp)
                {
                    deviceIp = value;
                }
            }
        }
        /// <summary>
        /// 图像数据RAW
        /// </summary>
        private byte[] rawData;
        public byte[] RawData { get => rawData; }
        /// <summary>
        /// 图像数据长度
        /// </summary>
        private int rawLen;
        public int RawLen { get => rawLen; }
        /// <summary>
        /// 图像数据指针
        /// </summary>
        private IntPtr rawPtr;
        public IntPtr RawPtr { get => rawPtr; }
        /// <summary>
        /// 图像宽度
        /// </summary>
        private int nwidth;
        public int Width { get => nwidth; }
        /// <summary>
        /// 图像高度
        /// </summary>
        private int nheight;
        public int Height { get => nheight; }
        /// <summary>
        /// 图片所属工件
        /// </summary>
        private string uuid;
        public string Uuid
        {
            get => uuid;
            set
            {
                if (value != uuid)
                {
                    uuid = value;
                }
            }
        }
        /// <summary>
        /// 图片所属二维码
        /// </summary>
        private string qrcode;
        public string QrCode
        {
            get => qrcode;
            set
            {
                if (value != qrcode)
                {
                    qrcode = value;
                }
            }
        }
        /// <summary>
        /// 图片索引
        /// </summary>
        private int index;
        public int Index
        {
            get => index;
            set
            {
                if (value != index)
                {
                    index = value;
                }
            }
        }
        /// <summary>
        /// 相机名称
        /// </summary>
        private string cameraName;
        public string CameraName
        {
            get => cameraName;
            set
            {
                cameraName = value;
            }
        }
        private GrabLightTypeE lightType = GrabLightTypeE.RGBLight;
        /// <summary>
        /// 拍照对应光源
        /// </summary>
        public GrabLightTypeE LightType//-LZC
        {
            get { return lightType; }
            set { lightType = value; }
        }
        /// <summary>
        /// 光机投影下标
        /// </summary>
        private int dlpLocationIndex;
        public int DlpLocationIndex
        {
            get => dlpLocationIndex;
            set => dlpLocationIndex = value;
        }
        /// <summary>
        /// 光机图像下标
        /// </summary>
        private int dlpImageIndex;
        public int DlpImageIndex
        {
            get => dlpImageIndex;
            set => dlpImageIndex = value;
        }
        /// <summary>
        /// 像素格式
        /// </summary>
        public Int32 PixelType;
        /// <summary>
        /// 是否为彩色相机
        /// </summary>
        private bool isColor;
        public bool IsColor
        {
            get => isColor;
            set { isColor = value; }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public HikvisionData(IntPtr pData, int width, int hight, int len, int pixelType)
        {
            nwidth = width;
            nheight = hight;
            isColor = false;
            PixelType = pixelType;
            rawLen = len;
            rawData = new byte[len];
            rawPtr = Marshal.UnsafeAddrOfPinnedArrayElement(rawData, 0);
            if (pData != IntPtr.Zero)
            {
                Marshal.Copy(pData, rawData, 0, len);
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="width"></param>
        /// <param name="hight"></param>
        /// <param name="color"></param>
        public HikvisionData(int width, int height, bool color)
        {
            nwidth = width;
            nheight = height;
            isColor = color;
            rawLen = color ? 3 * width * height : width * height;
            rawData = new byte[rawLen];
            rawPtr = Marshal.UnsafeAddrOfPinnedArrayElement(rawData, 0);
        }
        /// <summary>
        /// 指针之间进行数据拷贝
        /// </summary>
        /// <param name="pDst">目标地址</param>
        /// <param name="pSrc">源地址</param>
        /// <param name="len">拷贝数据长度</param>
        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", CharSet = CharSet.Ansi)]
        internal static extern void CopyMemory(IntPtr pDst, IntPtr pSrc, int len);

        /// <summary>
        /// raw转bmp
        /// </summary>
        /// <returns></returns>
        public Bitmap ToBitmap(/*IntPtr pdata, int width, int height, bool isColor*/)
        {
            PixelFormat format = isColor ? PixelFormat.Format24bppRgb : PixelFormat.Format8bppIndexed;
            Bitmap bmp = new Bitmap(nwidth, nheight, format);
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, nwidth, nheight),
                                                    ImageLockMode.WriteOnly, format);

            int imageStride = isColor ? nwidth * 3 : nwidth;
            if (imageStride == bmpData.Stride)
            {
                CopyMemory(bmpData.Scan0, rawPtr, bmpData.Stride * bmp.Height);
            }
            else
            {
                //for (int i = 0; i < bmp.Height; ++i)
                //{
                //    CopyMemory(bmpData.Scan0, pdata, bmpData.Stride * bmp.Height);
                //    Marshal.Copy(imgData, i * imageStride, new IntPtr(bmpData.Scan0.ToInt64() + i * bmpData.Stride), width);
                //}
            }

            bmp.UnlockBits(bmpData);

            if (bmp.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                ColorPalette tempPalette;
                using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
                {
                    tempPalette = tempBmp.Palette;
                }
                for (int i = 0; i < 256; i++)
                {
                    tempPalette.Entries[i] = Color.FromArgb(i, i, i);
                }

                bmp.Palette = tempPalette;
            }

            return bmp;
        }

    }

    public class HikvisionGrab : ICamera
    {
        /// <summary>
        /// 图像信息
        /// </summary>
        private struct ImageInfo
        {
            public uint Width;
            public uint Height;
            public uint PixelType;
        }

        /// <summary>
        /// 日志事件回调
        /// </summary>
        public Action<string> LogoutCallBack { get; set; }
        /// <summary>
        /// 图像事件回调
        /// </summary>
        public Action<IFrameData> ImageCallBack { get; set; }
        /// <summary>
        /// 曝光事件回调
        /// </summary>
        public Action<string> ExposureCallBack { get; set; }
        /// <summary>
        /// 触发结束回调
        /// </summary>
        public Action<string> TriggerEndCallBack { get; set; }
        /// <summary>
        /// 注册图像抓拍结束回调
        /// </summary>
        public Action<string> GrabEndCallback { get; set; }
        /// <summary>
        /// 注册帧重拍回调
        /// </summary>
        public Action<string, Int32> RemakeCallback { get; set; }
        /// <summary>
        /// 图像处理线程
        /// </summary>
        private Thread m_imageHandlerThread = null;
        /// <summary>
        /// 图像处理线程循环标志
        /// </summary>
        private bool m_bHandlerLoop = false;
        /// <summary>
        /// 图像帧队列
        /// </summary>
        private ConcurrentQueue<HikvisionData> m_frameList;
        /// <summary>
        /// 图像帧信息队列
        /// </summary>
        private ConcurrentQueue<FrameInfo> m_frameInfo;
        /// <summary>
        /// 硬件触发信息
        /// </summary>
        private FrameInfo m_hardTriggerInfo;
        /// <summary>
        /// 相机设备
        /// </summary>
        private CCamera device;
        /// <summary>
        /// 图像事件
        /// </summary>
        private cbOutputExdelegate m_cbOutput;
        /// <summary>
        /// 曝光事件
        /// </summary>
        private cbEventdelegateEx m_cbEvent;
        /// <summary>
        /// 异常回调
        /// </summary>
        private cbExceptiondelegate pCallBackFunc;
        /// <summary>
        /// 设备信息
        /// </summary>
        private CCameraInfo stDevice;
        /// <summary>
        /// 图像信息
        /// </summary>
        private ImageInfo m_ImageInfo = new ImageInfo();
        /// <summary>
        /// 连接状态
        /// </summary>
        private bool isConnected;
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected { get => isConnected; }
        /// <summary>
        /// 设备信息
        /// </summary>
        public CamInfo Info { get; set; }
        /// <summary>
        /// 触发模式
        /// </summary>
        private bool m_triggerMode = false;
        /// <summary>
        /// 触发源
        /// </summary>
        private uint m_triggerSource = 0;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="devInfo"></param>
        public HikvisionGrab()
        {
            device = new CCamera();
            m_frameList = new ConcurrentQueue<HikvisionData>();
            m_frameInfo = new ConcurrentQueue<FrameInfo>();

            m_bHandlerLoop = true;
            m_imageHandlerThread = new Thread(new ThreadStart(ImageHandlerThread));
            m_imageHandlerThread.IsBackground = true;
            m_imageHandlerThread.Start();
        }
        /// <summary>
        /// 搜索设备
        /// </summary>
        /// <param name="DevList"></param>
        public static List<ICamera> SearchDeviceList()
        {
            List<ICamera> cameraList = new List<ICamera>();
            List<CCameraInfo> ltDeviceList = new List<CCameraInfo>();
            int nRet = CSystem.EnumDevices(CSystem.MV_GIGE_DEVICE | CSystem.MV_USB_DEVICE, ref ltDeviceList);
            if (CErrorDefine.MV_OK != nRet)
            {
                return cameraList;
            }

            for (int i = 0; i < ltDeviceList.Count; i++)
            {
                CamInfo info = new CamInfo();
                if (CSystem.MV_GIGE_DEVICE == ltDeviceList[i].nTLayerType)
                {
                    CGigECameraInfo cGigEDeviceInfo = (CGigECameraInfo)ltDeviceList[i];

                    info.strSN = cGigEDeviceInfo.chSerialNumber;
                    info.strName = cGigEDeviceInfo.UserDefinedName;
                    uint nIp1 = ((cGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
                    uint nIp2 = ((cGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
                    uint nIp3 = ((cGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
                    uint nIp4 = (cGigEDeviceInfo.nCurrentIp & 0x000000ff);
                    info.strIP = nIp1.ToString() + "." + nIp2.ToString() + "." + nIp3.ToString() + "." + nIp4.ToString();
                    info.strManuf = cGigEDeviceInfo.chManufacturerName;
                    info.strModelName = cGigEDeviceInfo.chModelName;
                    if (cGigEDeviceInfo.chModelName.Contains("MV-C"))
                    {
                        cameraList.Add(new HikvisionGrab()
                        {
                            stDevice = ltDeviceList[i],
                            Info = info,
                        });
                    }
                }
                else if (CSystem.MV_USB_DEVICE == ltDeviceList[i].nTLayerType)
                {
                    CUSBCameraInfo cUsb3DeviceInfo = (CUSBCameraInfo)ltDeviceList[i];

                    info.strSN = cUsb3DeviceInfo.chSerialNumber;
                    info.strName = cUsb3DeviceInfo.UserDefinedName;
                    info.strManuf = cUsb3DeviceInfo.chManufacturerName;
                    info.strModelName = cUsb3DeviceInfo.chModelName;
                    if (cUsb3DeviceInfo.chModelName.Contains("MV-C"))
                    {
                        cameraList.Add(new HikvisionGrab()
                        {
                            stDevice = ltDeviceList[i],
                            Info = info,
                        });
                    }
                }
            }

            return cameraList;
        }
        /// <summary>
        /// 打开相机
        /// </summary>
        /// <param name="pDevInfo"></param>
        public bool OpenDevice()
        {
            int nRet;

            nRet = device.CreateHandle(ref stDevice);
            ApiCheckHandle("CreateHandle", nRet);
            if (nRet != CErrorDefine.MV_OK)
            {
                return false;
            }

            nRet = device.OpenDevice();
            ApiCheckHandle("OpenDevice", nRet);
            if (nRet != CErrorDefine.MV_OK)
            {
                device.DestroyHandle();
                return false;
            }
            isConnected = true;

            pCallBackFunc = new cbExceptiondelegate(cbExceptiondelegate);
            device.RegisterExceptionCallBack(pCallBackFunc, IntPtr.Zero);

            if (CSystem.MV_GIGE_DEVICE == stDevice.nTLayerType)
            {
                int nPacketSize = device.GIGE_GetOptimalPacketSize();
                if (nPacketSize > 0)
                {
                    nRet = device.SetIntValue("GevSCPSPacketSize", (uint)nPacketSize);
                    ApiCheckHandle("SetIntValue GevSCPSPacketSize", nRet);
                }
                // 设置心跳时间短 相机会出现掉线
                nRet = device.SetIntValue("GevHeartbeatTimeout", 20000);
                ApiCheckHandle("SetIntValue (GevHeartbeatTimeout, 20000)", nRet);
            }

            m_cbOutput = new cbOutputExdelegate(ImageCallbackFunc);
            nRet = device.RegisterImageCallBackEx(m_cbOutput, IntPtr.Zero);
            ApiCheckHandle("RegisterImageCallBackEx", nRet);
            if (nRet != CErrorDefine.MV_OK)
            {
                device.CloseDevice();
                device.DestroyHandle();
                return false;
            }

            m_cbEvent = new cbEventdelegateEx(EventCallbackFunc);
            nRet = device.RegisterEventCallBackEx("ExposureEnd", m_cbEvent, IntPtr.Zero);
            if (nRet != CErrorDefine.MV_OK && nRet != CErrorDefine.MV_E_SUPPORT && nRet != CErrorDefine.MV_E_PARAMETER)
            {
                ApiCheckHandle("RegisterEventCallBackEx ExposureEnd", nRet);
                device.CloseDevice();
                device.DestroyHandle();
                return false;
            }

            CIntValue value = new CIntValue();
            nRet = device.GetIntValue("Width", ref value);
            if (nRet != CErrorDefine.MV_OK)
            {
                ApiCheckHandle("MV_CC_GetWidth_NET", nRet);
                return false;
            }
            m_ImageInfo.Width = (uint)value.CurValue;

            nRet = device.GetIntValue("Height", ref value);
            if (nRet != CErrorDefine.MV_OK)
            {
                ApiCheckHandle("MV_CC_GetHeight_NET", nRet);
                return false;
            }
            m_ImageInfo.Height = (uint)value.CurValue;

            CEnumValue enumValue = new CEnumValue();
            nRet = device.GetEnumValue("PixelFormat", ref enumValue);
            if (nRet != CErrorDefine.MV_OK)
            {
                ApiCheckHandle("MV_CC_GetPixelFormat_NET", nRet);
                return false;
            }
            m_ImageInfo.PixelType = enumValue.CurValue;

            nRet = device.SetImageNodeNum(2);
            ApiCheckHandle("SetImageNodeNum", nRet);

            nRet = device.SetEnumValueByString("EventSelector", "ExposureEnd");
            //ApiCheckHandle("SetEnumValueByString EventSelector ExposureEnd", nRet);

            nRet = device.SetEnumValueByString("EventNotification", "On");
            //ApiCheckHandle("SetEnumValueByString EventNotification", nRet);

            return true;
        }
        /// <summary>
        /// 关闭相机
        /// </summary>
        public void CloseDevice()
        {
            int nRet = device.CloseDevice();
            ApiCheckHandle("CloseDevice", nRet);

            nRet = device.DestroyHandle();
            ApiCheckHandle("DestroyHandle", nRet);

            isConnected = false;
        }
        /// <summary>
        /// 启动抓拍
        /// </summary>
        public void StartGrab()
        {
            int nRet = device.StartGrabbing();
            ApiCheckHandle("StartGrabbing", nRet);
        }
        /// <summary>
        /// 停止抓拍
        /// </summary>
        public void StopGrab()
        {
            int nRet = device.StopGrabbing();
            ApiCheckHandle("StopGrabbing", nRet);
        }
        /// <summary>
        /// 设置图像宽度
        /// </summary>
        /// <param name="width"></param>
        public int SetImageWidth(uint width)
        {
            int nRet = device.SetIntValue("Width", width);
            ApiCheckHandle("SetImageWidth", nRet);
            return nRet;
        }
        /// <summary>
        /// 设置图像高度
        /// </summary>
        /// <param name="height"></param>
        public int SetImageHeight(uint height)
        {
            int nRet = device.SetIntValue("Height", height);
            ApiCheckHandle("SetImageHeight", nRet);
            return nRet;
        }
        /// <summary>
        /// 设置触发选择器
        /// </summary>
        /// <param name="selector"></param>
        public void SetTriggerSelector(uint selector)
        {
            int nRet = 0;
            if (selector == 0)
            {
                nRet = device.SetEnumValueByString("TriggerSelector", "FrameBurstStart");
            }
            else
            {
                nRet = device.SetEnumValueByString("TriggerSelector", "LineStart");
            }
            ApiCheckHandle("SetTriggerSelector", nRet);
        }
        /// <summary>
        /// 设置触发极限
        /// </summary>
        /// <param name="activation">0-上升沿 1-下降沿 2-高电平 3-低电平 4-双边沿</param>
        public void SetTriggerActivation(uint activation)
        {
            int nRet = device.SetEnumValue("TriggerActivation", activation);
            ApiCheckHandle("SetTriggerActivation", nRet);
        }
        /// <summary>
        /// 设置触发模式 false-触发关闭(持续)  true-触发打开
        /// </summary>
        /// <param name="mode"></param>
        public void SetTriggerMode(bool mode)
        {
            int nRet;

            m_triggerMode = mode;

            if (mode)
            {
                nRet = device.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
            }
            else
            {
                nRet = device.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
            }

            ApiCheckHandle("SetTriggerMode", nRet);
        }
        /// <summary>
        /// 设置触发源
        /// </summary>
        /// <param name="triggerSource">0-线性0  1-软件</param>
        public void SetTriggerSource(uint triggerSource)
        {
            int nRet = 0;

            m_triggerSource = triggerSource;

            if (triggerSource == 0)
            {
                nRet = device.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
            }
            else if (triggerSource == 1)
            {
                nRet = device.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
            }
            else if (triggerSource == 2)
            {
                nRet = device.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE1);
            }

            ApiCheckHandle("SetEnumValue TriggerSource", nRet);
        }
        /// <summary>
        /// 设置曝光时间
        /// </summary>
        /// <param name="expTime"></param>
        public void SetExposureTime(float expTime)
        {
            int nRet = device.SetEnumValue("ExposureAuto", 0);
            ApiCheckHandle("SetEnumValue ExposureAuto", nRet);

            nRet = device.SetFloatValue("ExposureTime", expTime);
            ApiCheckHandle("SetFloatValue ExposureTime", nRet);
        }
        /// <summary>
        /// 获取曝光时间
        /// </summary>
        /// <param name="gain"></param>
        public void GetExposureTime(ref float expTime)
        {
            CFloatValue val = new CFloatValue();
            int nRet = device.GetFloatValue("ExposureTime", ref val);
            ApiCheckHandle("GetFloatValue ExposureTime", nRet);

            expTime = val.CurValue;
        }
        /// <summary>
        /// 设置部分图像输出模式
        /// </summary>
        /// <param name="mode">0-ImagePending 1-PartialImageOutput 
        /// 2-PartialImageDiscard 3-PartialImageFilled</param>
        public void SetPartialImageOutputMode(uint mode)
        {
            int nRet = device.SetEnumValue("PartialImageOutputMode", mode);
            ApiCheckHandle("SetPartialImageOutputMode", nRet);
        }
        /// <summary>
        /// 设置线性使能
        /// </summary>
        /// <param name="enable"></param>
        public void SetAbnormalLineEnable(bool enable)
        {
            int nRet = device.SetBoolValue("AbnormalLineEnable", enable);
            ApiCheckHandle("SetAbnormalLineEnable", nRet);
        }
        /// <summary>
        /// 设置增益值
        /// </summary>
        /// <param name="gain"></param>
        public void SetGainValue(float gain)
        {
            int nRet = device.SetEnumValue("GainAuto", 0);
            ApiCheckHandle("SetEnumValue GainAuto", nRet);

            nRet = device.SetFloatValue("Gain", gain);
            ApiCheckHandle("SetFloatValue Gain", nRet);
        }
        /// <summary>
        /// 获取增益值
        /// </summary>
        /// <param name="gain"></param>
        public void GetGainValue(ref float gain)
        {
            CFloatValue val = new CFloatValue();
            int nRet = device.GetFloatValue("Gain", ref val);
            ApiCheckHandle("GetFloatValue Gain", nRet);

            gain = val.CurValue;
        }
        /// <summary>
        /// 旋转图像
        /// </summary>
        /// <param name="sImg"></param>
        /// <param name="dImg"></param>
        /// <param name="angle"></param>
        public void RotateImage(ref HikvisionData sImg, ref HikvisionData dImg, uint angle)
        {
            CRotateImageParam rotate = new CRotateImageParam();

            rotate.InImage.PixelType = (MvGvspPixelType)sImg.PixelType;
            rotate.InImage.Width = (ushort)sImg.Width;
            rotate.InImage.Height = (ushort)sImg.Height;
            rotate.InImage.ImageAddr = sImg.RawPtr;
            rotate.InImage.ImageSize = (uint)sImg.RawLen;
            rotate.OutImage.ImageAddr = dImg.RawPtr;
            rotate.OutImage.ImageSize = (uint)dImg.RawLen;
            rotate.RotationAngle = (MV_IMG_ROTATION_ANGLE)angle;

            int nRet = device.RotateImage(ref rotate);
            ApiCheckHandle("RotateImage", nRet);
        }
        /// <summary>
        /// 设置硬件触发图片信息
        /// </summary>
        /// <param name="uuid"></param>
        /// <param name="code"></param>
        /// <param name="index"></param>
        /// <param name="total"></param>
        /// <returns></returns>
        public void SetHardTriggerInfo(FrameInfo info)
        {
            m_hardTriggerInfo = info;
        }
        /// <summary>
        /// 软件触发
        /// </summary>
        public void SoftwareTrigger()
        {
            int nRet = device.SetCommandValue("TriggerSoftware");
            if (nRet != CErrorDefine.MV_OK)
            {
                ApiCheckHandle("SetCommandValue(TriggerSoftware)", nRet);
            }
        }
        /// <summary>
        /// 软件触发
        /// </summary>
        public void SoftwareTrigger(string uuid, string code, int index)
        {
            int nRet;

            FrameInfo inf = new FrameInfo();
            inf.uuid = uuid;
            inf.code = code;
            inf.index = index;

            if (index == 0)
            {
                while (!m_frameInfo.IsEmpty)
                {
                    m_frameInfo.TryDequeue(out FrameInfo hik);
                }
            }

            m_frameInfo.Enqueue(inf);

            SoftwareTrigger();
        }

        /// <summary>
        /// 软件触发
        /// </summary>
        public Int32 SoftwareTrigger(FrameInfo info)
        {
            int nRet = 0;
            FrameInfo inf = info;

            if (inf.IsBlackPatch)
            {
                if (m_frameInfo.IsEmpty)
                {
                    HikvisionData frameData = new HikvisionData(IntPtr.Zero, (int)m_ImageInfo.Width, (int)m_ImageInfo.Height,
        (int)(3 * m_ImageInfo.Width * m_ImageInfo.Height), (int)m_ImageInfo.PixelType);

                    frameData.Uuid = inf.uuid;
                    frameData.QrCode = inf.code;
                    frameData.Index = inf.index;
                    frameData.LightType = inf.LightType;

                    m_frameList.Enqueue(frameData);
                }
                else
                {
                    m_frameInfo.Enqueue(inf);
                }

                ExposureCallBack?.Invoke(Info.strSN);
                GrabEndCallback?.Invoke(Info.strSN);
            }
            else
            {
                m_frameInfo.Enqueue(inf);
                SoftwareTrigger();
            }

            return nRet;
        }
        /// <summary>
        /// 清除拍照Info队列 -LZC
        /// </summary>
        public void ClearGrabInfo()
        {
            while (!m_frameInfo.IsEmpty)
            {
                m_frameInfo.TryDequeue(out FrameInfo hik);
            }
        }
        /// <summary>
        /// 事件回调函数
        /// </summary>
        /// <param name="pEventInfo"></param>
        /// <param name="pUser"></param>
        private void EventCallbackFunc(ref MV_EVENT_OUT_INFO pEventInfo, IntPtr pUser)
        {
            if (pEventInfo.EventName == "ExposureEnd")
            {
                ExposureCallBack?.Invoke(Info.strSN);
            }
        }

        /// <summary>
        /// 图像回调处理
        /// </summary>
        /// <param name="pData"></param>
        /// <param name="pFrameInfo"></param>
        /// <param name="pUser"></param>
        private void ImageCallbackFunc(IntPtr pData, ref MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            HikvisionData frame = new HikvisionData(pData, pFrameInfo.nWidth, pFrameInfo.nHeight,
                (int)pFrameInfo.nFrameLen, (int)pFrameInfo.enPixelType);

            if (m_frameInfo.Count == 0)
            {
                if (pFrameInfo.nLostPacket != 0)
                {
                    Logger.Logout($"检测到有丢包图像帧:{m_hardTriggerInfo.index}");
                    return;
                }
               
                frame.Uuid = m_hardTriggerInfo.uuid;
                frame.QrCode = m_hardTriggerInfo.code;
                frame.Index = m_hardTriggerInfo.index;
                frame.LightType = m_hardTriggerInfo.LightType;
                frame.DlpLocationIndex = m_hardTriggerInfo.DlpLocationIndex;
                frame.DlpImageIndex = m_hardTriggerInfo.DlpImageIndex++;
                //m_hardTriggerInfo.index++;
                GrabEndCallback?.Invoke(Info.strSN);//-LZC
                m_frameList.Enqueue(frame);
            }
            else
            {
                FrameInfo inf = new FrameInfo();
                if (m_frameInfo.TryDequeue(out inf))
                {
                    if (inf.IsBlackPatch)
                    {
                        HikvisionData frameData = new HikvisionData(IntPtr.Zero, pFrameInfo.nWidth, pFrameInfo.nHeight,
                                (int)pFrameInfo.nFrameLen, (int)pFrameInfo.enPixelType);

                        frameData.Uuid = inf.uuid;
                        frameData.QrCode = inf.code;
                        frameData.Index = inf.index;
                        frameData.LightType = inf.LightType;

                        m_frameList.Enqueue(frameData);
                    }
                    else
                    {
                        frame.Uuid = inf.uuid;
                        frame.QrCode = inf.code;
                        frame.Index = inf.index;
                        frame.LightType = inf.LightType;
                        if (pFrameInfo.nLostPacket != 0)
                        {
                            Logger.Logout("检测到有丢包图像帧:" + frame.Index.ToString());
                            RemakeCallback?.Invoke(Info.strSN, frame.Index);
                            return;
                        }
                        GrabEndCallback?.Invoke(Info.strSN);//-LZC
                        m_frameList.Enqueue(frame);
                    }
                }
            }
        }
        private bool IsMonoPixelFormat(MvGvspPixelType enType)
        {
            switch (enType)
            {
                case MvGvspPixelType.PixelType_Gvsp_Mono10:
                case MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case MvGvspPixelType.PixelType_Gvsp_Mono12:
                case MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                    return true;
                default:
                    return false;
            }
        }

        private bool IsColorPixelFormat(MvGvspPixelType enType)
        {
            switch (enType)
            {
                case MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
                //case MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
                case MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
                case MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerGR8:
                case MvGvspPixelType.PixelType_Gvsp_BayerRG8:
                case MvGvspPixelType.PixelType_Gvsp_BayerGB8:
                case MvGvspPixelType.PixelType_Gvsp_BayerBG8:
                case MvGvspPixelType.PixelType_Gvsp_BayerGB10:
                case MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerBG10:
                case MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerRG10:
                case MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerGR10:
                case MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerGB12:
                case MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerBG12:
                case MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerRG12:
                case MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
                case MvGvspPixelType.PixelType_Gvsp_BayerGR12:
                case MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
                    return true;
                default:
                    return false;
            }
        }
        /// <summary>
        /// 图像处理线程
        /// </summary>
        private void ImageHandlerThread()
        {
            try
            {
                while (m_bHandlerLoop)
                {
                    if (m_frameList.IsEmpty)
                    {
                        ThreadHelper.Delay(1);
                        continue;
                    }

                    m_frameList.TryDequeue(out HikvisionData frame);

                    MvGvspPixelType DstPixelType = MvGvspPixelType.PixelType_Gvsp_Undefined;
                    bool frameColor = false;
                    if (IsColorPixelFormat((MvGvspPixelType)frame.PixelType))
                    {
                        DstPixelType = MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
                        frameColor = true;
                    }
                    else if (IsMonoPixelFormat((MvGvspPixelType)frame.PixelType))
                    {
                        DstPixelType = MvGvspPixelType.PixelType_Gvsp_Mono8;
                        frameColor = false;
                    }
                    else if ((MvGvspPixelType)frame.PixelType == MvGvspPixelType.PixelType_Gvsp_BGR8_Packed)
                    {
                        frame.IsColor = true;
                    }

                    if (DstPixelType != MvGvspPixelType.PixelType_Gvsp_Undefined)
                    {
                        IFrameData frameData = new HikvisionData(frame.Width, frame.Height, frameColor);
                        CPixelConvertParam pstCvtParam = new CPixelConvertParam();

                        frameData.Uuid = frame.Uuid;
                        frameData.QrCode = frame.QrCode;
                        frameData.Index = frame.Index;
                        frameData.LightType = frame.LightType;
                        frameData.DlpLocationIndex = frame.DlpLocationIndex;
                        frameData.DlpImageIndex = frame.DlpImageIndex;
                        frameData.SerialNo = Info.strSN;
                        frameData.DeviceIp = Info.strIP;
                        frameData.CameraName = Info.strName;

                        pstCvtParam.InImage = new CImage(frame.RawPtr, (MvGvspPixelType)frame.PixelType, (uint)frame.RawLen, (ushort)frame.Height, (ushort)frame.Width, 0, 0);
                        pstCvtParam.OutImage.PixelType = DstPixelType;
                        device.ConvertPixelType(ref pstCvtParam);
                        Marshal.Copy(pstCvtParam.OutImage.ImageAddr, frameData.RawData, 0, (int)pstCvtParam.OutImage.ImageSize);
                        Logout($"{Info.strSN},图像Index:{frameData.Index},光源类型:{frame.LightType}");
                        
                        ImageCallBack?.Invoke(frameData);
                    }
                    else
                    {
                        frame.SerialNo = Info.strSN;
                        frame.DeviceIp = Info.strIP;
                        frame.CameraName = Info.strName;
                        Logout($"{Info.strSN},图像Index:{frame.Index}");
                        
                        ImageCallBack?.Invoke(frame);
                    }
                }
            }
            catch(Exception ex)
            {
                Logout($"{ex}");
            }
        }
        /// <summary>
        /// 异常回调
        /// </summary>
        /// <param name="nMsgType"></param>
        /// <param name="pUser"></param>
        private void cbExceptiondelegate(uint nMsgType, IntPtr pUser)
        {
            if (nMsgType == MyCamera.MV_EXCEPTION_DEV_DISCONNECT)
            {
                StopGrab();
                CloseDevice();
                Reconnect();
            }
        }
        /// <summary>
        /// 重连相机
        /// </summary>
        private void Reconnect()
        {
            while (true)
            {
                if (OpenDevice())
                {
                    // 需重设相机参数,相机掉线有网络掉线和掉电掉线
                    //SetTriggerMode(m_triggerMode);
                    //SetTriggerSource(m_triggerSource);
                    StartGrab();
                    Logout(Info.strSN + "相机重连成功.");
                    break;
                }
                ThreadHelper.Delay(2000);
            }
        }
        public void Dispose()
        {
            m_bHandlerLoop = false;
            //m_imageHandlerThread.Abort();
            StopGrab();
            CloseDevice();
            Logout("释放相机.");
        }
        /// <summary>
        /// 相机API异常日志
        /// </summary>
        /// <param name="api"></param>
        /// <param name="nRet"></param>
        private void ApiCheckHandle(string api, int nRet)
        {
            if (nRet != CErrorDefine.MV_OK)
            {
                Logout(api + " StatusCode:" + nRet.ToString("X2") + "strSN:" + Info.strSN);
            }
        }
        /// <summary>
        /// 日志输出
        /// </summary>
        /// <param name="logtxt"></param>
        private void Logout(string logtxt)
        {
            LogoutCallBack?.Invoke($"{Info.strName}:{logtxt}");
        }
    }
}
